package yartiss.gui.graphics.rendrerers;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableRowSorter;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRenderer;

import yartiss.engine.simulation.IEnergyProfile;
import yartiss.engine.simulation.ISchedulingPolicy;
import yartiss.engine.simulation.SimulationParameters;
import yartiss.engine.simulation.energy.profiles.EnergyProfileFactory;
import yartiss.engine.simulation.scheduling.policies.SchedulingPolicyFactory;
import yartiss.engine.simulation.system.ITask;
import yartiss.gui.graphics.IChartRenderer;
import yartiss.gui.view.TimelineView;
import yartiss.service.model.Scenario;
import yartiss.service.model.TasksSetsTableModel;
import yartiss.service.model.TasksSetsTableModel.Result;
import yartiss.service.model.TasksSetsTableModel.TaskSetEntry;
import yartiss.service.model.TasksTableModel;
import yartiss.service.viewmodel.TimeLineViewModel;

public class BarChartRenderer implements IChartRenderer<Scenario> {

	@Override
	public JInternalFrame render(final Scenario model, boolean isDebug) {
		JInternalFrame frame = new JInternalFrame(model.getScenarioName(),true,true,true,true);
		JPanel root = new JPanel(new BorderLayout());

		JFreeChart barChart = ChartFactory.createBarChart("", "", "", model.getData(),PlotOrientation.VERTICAL, true, true, false);
		
		CategoryPlot plot = (CategoryPlot) barChart.getPlot();
		CategoryAxis domainAxis = plot.getDomainAxis();
		domainAxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(Math.PI / 6.0));
		
		NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setUpperMargin(0.15);
        
        CategoryItemRenderer renderer = plot.getRenderer();        
        renderer.setSeriesItemLabelsVisible(0, Boolean.TRUE);
		
		ChartPanel panel = new ChartPanel(barChart);
		JProgressBar progressBar = new JProgressBar(model.getProgressModel());
		
		if(isDebug){
			JButton showSets = new JButton("Show systems");
			showSets.addActionListener(new ActionListener() {
				@Override  	public void actionPerformed(ActionEvent e) {
					showTasksSet(model.getSetsModel(), model.getScenarioName());
				}
			});
			root.add(showSets, BorderLayout.SOUTH);
		}

		root.add(panel, BorderLayout.CENTER);
		root.add(progressBar, BorderLayout.NORTH);
		frame.setContentPane(root);
		frame.setVisible(true);
		return 	frame;
	}


	public static void showTasksSet(final TasksSetsTableModel model, String scenarioName){
		JFrame window = new JFrame("RTSS-"+scenarioName);
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension d = new Dimension(screenSize);
		d.width  *= (5.0 / 6.0);
		d.height *= (5.0 / 6.0);
		window.setBounds((screenSize.width - d.width) / 2, (screenSize.height - d.height) / 2, d.width, d.height);
		window.setPreferredSize(d);

		final JTable table = new JTable(model);
		final TableCellRenderer old = table.getDefaultRenderer(Object.class);
		table.setDefaultRenderer(Object.class, new TableCellRenderer() {
			@Override
			public Component getTableCellRendererComponent(JTable table, Object value,	boolean isSelected, boolean hasFocus, int row, int column) {
				Component comp =  old.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
				if(column > 3){
					Color c = Color.green;
					if(!value.toString().equals(Result.SUCCESS.toString())){
						if(value.toString().equals(Result.DEADLINE_MISSED.toString()))
							c = Color.red;
						else c = Color.orange;
					}
					comp.setBackground(c);
					return comp;
				}
				else if(column == 1){
					Color c = value.equals(false) ? Color.red : Color.green;
					comp.setBackground(c);
					return comp;
				}
				comp.setBackground(Color.WHITE);
				return comp;
			}
		});
		table.setDefaultRenderer(Boolean.class, new TableCellRenderer() {
			@Override	public Component getTableCellRendererComponent(JTable table, Object value,	boolean isSelected, boolean hasFocus, int row, int column) {
				System.out.println("toto");
				return null;
			}
		});


		final TableRowSorter<TasksSetsTableModel> sorter = new TableRowSorter<TasksSetsTableModel>(model);
		sorter.setComparator(0, new Comparator<Integer>() {
			@Override public int compare(Integer o1, Integer o2) {
				return o1 - o2;
			}
		});

		table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			private int lastRow = -1;
			@Override
			public void valueChanged(ListSelectionEvent e) {
				int selectedRow = table.getSelectedRow();
				if(selectedRow == lastRow)return;
				lastRow = selectedRow;
				if(selectedRow>=0){
					TaskSetEntry entry = model.getRow(table.convertRowIndexToModel(selectedRow));
					for (int i = 4; i < model.getColumnCount(); i++) {
						ISchedulingPolicy policy = SchedulingPolicyFactory.getInstance(model.getColumnName(i));
						IEnergyProfile ep = EnergyProfileFactory.getInstance("default", (int)entry.energyProfile.getPowerRate(),(int)entry.energyProfile.getMaxEnergyLevel(),(int)entry.energyProfile.getMinEnergyLevel(),(int)entry.energyProfile.getStartEnergyLevel() );
						showChronogramme(new SimulationParameters(policy, entry.simulationDura, ep, entry.set,1, true));
					}
				}
			}
		});

		List <RowSorter.SortKey> sortKeys   = new ArrayList<RowSorter.SortKey>();
		sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));
		sorter.setSortKeys(sortKeys);
		table.setRowSorter(sorter);
		JScrollPane scPane = new JScrollPane(table);

		final String [] filterTypes = new String []{"NONE", Result.SUCCESS.toString(), Result.DEADLINE_MISSED.toString(), Result.ENERGY_FAILURE.toString(), "DIFFERENCE"};
		final JComboBox<String> combo = new JComboBox<String>(filterTypes);
		combo.addActionListener(new ActionListener() {
			@Override 	public void actionPerformed(ActionEvent e) {
				int filterType = combo.getSelectedIndex();
				switch (filterType) {
				case 0: sorter.setRowFilter(null);break;
				case 1: sorter.setRowFilter(new RowFilter<Object, Object>() {
					@Override	public boolean include(javax.swing.RowFilter.Entry<? extends Object, ? extends Object> entry) {
						for (int i = 4; i < entry.getValueCount(); i++) {
							if(!entry.getStringValue(i).equals(Result.SUCCESS.toString()))
								return false;
						}
						return true;
					}
				});	
				break;
				case 2: sorter.setRowFilter(new RowFilter<Object, Object>() {
					@Override	public boolean include(javax.swing.RowFilter.Entry<? extends Object, ? extends Object> entry) {
						for (int i = 4; i < entry.getValueCount(); i++) {
							if(!entry.getStringValue(i).equals(Result.DEADLINE_MISSED.toString()))
								return false;
						}
						return true;
					}
				});	
				break;
				case 3: sorter.setRowFilter(new RowFilter<Object, Object>() {
					@Override	public boolean include(javax.swing.RowFilter.Entry<? extends Object, ? extends Object> entry) {
						for (int i = 4; i < entry.getValueCount(); i++) {
							if(!entry.getStringValue(i).equals(Result.ENERGY_FAILURE.toString()))
								return false;
						}
						return true;
					}
				});	
				break;
				case 4: sorter.setRowFilter(new RowFilter<Object, Object>() {
					@Override	public boolean include(javax.swing.RowFilter.Entry<? extends Object, ? extends Object> entry) {
						String val1 = entry.getStringValue(4);
						for (int i = 5; i < entry.getValueCount(); i++) {
							if(!entry.getStringValue(i).equals(val1))
								return true;
						}
						return false;
					}
				});	
				break;
				default:
					break;
				}
			}
		});
		JPanel panel = new JPanel(new BorderLayout());
		panel.add(scPane, BorderLayout.CENTER);
		panel.add(combo,BorderLayout.NORTH);
		window.setContentPane(panel);
		window.setVisible(true);
	}



	public static void showChronogramme(SimulationParameters parameters){

		JFrame window = new JFrame("RTSS-"+parameters.getSchedulingPolicy().getPolicyName()+"--"+parameters.getEnergyProfile().getMaxEnergyLevel()+"_"+parameters.getEnergyProfile().getPowerRate());
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension d = new Dimension(screenSize);
		d.width  *= (5.0 / 6.0);
		d.height *= (5.0 / 6.0);
		window.setBounds((screenSize.width - d.width) / 2, (screenSize.height - d.height) / 2, d.width, d.height);
		window.setPreferredSize(d);
		TimeLineViewModel vm = new TimeLineViewModel();

		vm.setE0((int) parameters.getEnergyProfile().getStartEnergyLevel());
		vm.setEmax((int) parameters.getEnergyProfile().getMaxEnergyLevel());
		vm.setEmin((int) parameters.getEnergyProfile().getMinEnergyLevel());
		vm.setPr((int) parameters.getEnergyProfile().getPowerRate());
		vm.setDuration((int) parameters.getSimulationEnd());
		vm.setPolicyParameters("");
		vm.setSelectedPolicyName(parameters.getSchedulingPolicy().getPolicyName());
		TasksTableModel tasksModel = vm.getTasksModel();
		tasksModel.clear();

		for (ITask task : parameters.getTaskSet()) {
			tasksModel.addRow(task.cloneTask());
		}

		TimelineView view = new TimelineView();

		vm.setView(view);
		JComponent root = (JComponent) vm.getView();

		window.setContentPane(root);
		window.setVisible(true);
		vm.getStartSimulationCommand().actionPerformed(null);
	}

}
